#!/usr/bin/python

import sys
import applib # You must install the applib directory in your Python module path.
from applib.logging import default_logger as log
from optparse import OptionParser

log.setName("applink")

# Parse options.
parser = OptionParser(usage="%prog [options] NAME VERSION")
applib.general.CommandLine.applyOptions(parser)
parser.add_option("-x", "--unlink", help="Unlink the application instead of linking it.", dest="app_unlink", action="store_true", default=False)
parser.add_option("-r", "--relink", help="Unlink and then link the application.  Use this instead of -x if you are relinking an essential system component (such as Glibc) since if said core component is not linked at any point you will not be able to re-run Python to link it again.", dest="app_relink", action="store_true", default=False)
parser.add_option("-v", "--verbose", help="Display additional information (such as directories still in use or files ignored because they aren't specifically owned by the application) during the link / unlink / relink process.", dest="verbose", action="store_true", default=False)
(options, args) = parser.parse_args()

log.setVerbose(options.verbose)

appname = None
appver = None

if (len(args) == 1):
	appname = args[0]
elif (len(args) == 2):
	appname = args[0]
	appver = args[1]
else:
	log.showErrorW("Invalid number arguments.  Type applink --help for usage information.")
	sys.exit(1)

# Get the application type from the command line arguments.
apptype = applib.general.CommandLine.getTypeFromOptions(options)

# Create an instance of InstalledApplication.
app = applib.fs.InstalledApplication(apptype, appname, appver)
try:
	app.autodetect()
except applib.general.NoVersionsException:
	log.showErrorW("Unable to detect the application version.  Specify it as a second parameter.")
	sys.exit(1)
except applib.general.MultipleVersionsException:
	log.showErrorW("More than one version of application detected.  Specify the version you")
	log.showErrorO("want to link as a second parameter.")
	sys.exit(1)
except applib.general.ApplicationNotFoundException:
	log.showErrorW("Unable to locate the application on disk (to scan for versions).")
	log.showErrorO("The location applink looked in was:")
	log.showErrorO("  * " + app.location_unversioned())
	sys.exit(1)

# Check to make sure the application exists.
if (not app.exists()):
	log.showErrorW("Unable to locate the application on disk.  The location applink looked in was:")
	log.showErrorO("  * " + app.location())
	sys.exit(1)

if (not options.app_unlink and not options.app_relink):
	log.showInfoW("Linking application " + app.name + ", version " + app.version + " to the root filesystem...", True);
	successes, failures, tot = app.link()
	tot = str(tot)
	
	if (len(failures) == 0):
		log.showSuccessW("Successfully linked all " + str(len(successes)) + " files (total on disk: " + tot + ").")
		log.showSuccessO("Remember to run ldconfig if the application contains library files.")
		sys.exit(0)
	elif (len(successes) > 0):
		log.showWarningW("Only " + str(len(successes)) + " of " + str(len(successes) + len(failures)) + " files were successfully linked (total on disk: " + tot + ").")
		log.showWarningO("Remember to run ldconfig if the application contains library files.")
		sys.exit(1)
	else:
		log.showErrorW("All " + str(len(failures)) + " files failed to link.  Make sure you have appropriate permissions. (total on disk: " + tot + ")")
		sys.exit(1)
elif (options.app_relink):
	log.showInfoW("Relinking application " + app.name + ", version " + app.version + " to the root filesystem...", True);
	ul_successes, ul_failures, ul_tot = app.unlink()
	rl_successes, rl_failures, rl_tot = app.link()

	c_successes = len(ul_successes) + len(rl_successes)
	c_failures = len(ul_failures) + len(rl_failures)
	tot = str(ul_tot + rl_tot)

	if (c_failures == 0):
		log.showSuccessW("Successfully performed all " + str(c_successes) + " relinking operations (total relinks attempted: " + tot + ").")
		log.showSuccessO("Remember to run ldconfig if the application contains library files.")
		sys.exit(0)
	elif (c_successes > 0):
		log.showWarningW("Only " + str(c_successes) + " of " + str(c_successes + c_failures) + " relinking operations were successful (total relinks attempted: " + tot + ").")
		log.showWarningO("Check to make sure applications still operate if it's a core library.")
		log.showWarningO("Remember to run ldconfig if the application contains library files.")
		sys.exit(1)
	else:
		log.showErrorW("All " + str(c_failures) + " of the relinking operations failed.  Make sure you have appropriate permissions (the system is unaffected).")
		sys.exit(1)
else:
	if (app.name == "Glibc" or app.name == "Python" or app.name == "Binutils"):
		log.showErrorW("Safety check triggered.  You have selected to unlink either:")
		log.showErrorO("  * Glibc")
		log.showErrorO("  * Python or")
		log.showErrorO("  * Binutils")
		log.showErrorO("all which are essential for the operation of other applications")
		log.showErrorO("and this script.  If you wish to relink these applications, use")
		log.showErrorO("the -r option instead.")
		sys.exit(1)

	log.showInfoW("Unlinking application " + app.name + ", version " + app.version + " from the root filesystem...", True);
	successes, failures, tot = app.unlink()
	tot = str(tot)

	if (len(failures) == 0):
		log.showSuccessW("Successfully unlinked all " + str(len(successes)) + " files (total in app: " + tot + ").")
		log.showSuccessO("Remember to run ldconfig if the application contains library files.")
		sys.exit(0)
	elif (len(successes) > 0):
		log.showWarningW("Only " + str(len(successes)) + " of " + str(len(successes) + len(failures)) + " files were successfully unlinked (total in app: " + tot + ").")
		log.showWarningO("Remember to run ldconfig if the application contains library files.")
		sys.exit(1)
	else:
		log.showErrorW("All " + str(len(failures)) + " files failed to unlink.  Make sure you have appropriate permissions. (total in app: " + tot + ")")
		sys.exit(1)
